#include <iostream>
#include "utf8_output.h"

// 一元右折叠：(args + ...)
// 展开为：(arg1 + (arg2 + (arg3 + arg4)))

// 一元左折叠：(... + args)
// 展开为：(((arg1 + arg2) + arg3) + arg4)

// 二元右折叠：(args + ... + value)
// 展开为：(arg1 + (arg2 + (arg3 + (arg4 + value))))

// 二元左折叠：(value + ... + args)
// 展开为：((((value + arg1) + arg2) + arg3) + arg4)

// 计算所有参数的和
template <typename... Args>
auto sum(Args... args)
{
    return (... + args);
}
// sum(1, 2, 3, 4) 会被展开为 ((1 + 2) + 3) + 4

// 检查所有参数是否为真
template <typename... Args>
bool all(Args... args)
{
    return (... && args);
}
// all(true, false, true) 会被展开为 ((true && false) && true)

// 用逗号连接所有参数的打印
template <typename... Args>
void print(Args... args)
{
    ((std::cout << args << ", "), ...);
}
// print(1, "hello", 3.14) 会打印：1, hello, 3.14,

// 1. 一元右折叠
template <typename... Args>
auto sum_right_unary(Args... args)
{
    return (args + ...); // 一元右折叠
}

// 2. 一元左折叠
template <typename... Args>
auto sum_left_unary(Args... args)
{
    return (... + args); // 一元左折叠
}

// 3. 二元右折叠
template <typename... Args>
auto sum_right_binary(Args... args)
{
    return (args + ... + 100); // 二元右折叠，100是初始值
}

// 4. 二元左折叠
template <typename... Args>
auto sum_left_binary(Args... args)
{
    return (100 + ... + args); // 二元左折叠，100是初始值
}

// 一元右折叠减法
template <typename... Args>
auto subtract_right(Args... args)
{
    return (args - ...); // 一元右折叠
}

// 一元左折叠减法
template <typename... Args>
auto subtract_left(Args... args)
{
    return (... - args); // 一元左折叠
}

// 二元右折叠减法（带初始值）
template <typename... Args>
auto subtract_right_binary(Args... args)
{
    return (args - ... - 1000); // 二元右折叠
}

// 二元左折叠减法（带初始值）
template <typename... Args>
auto subtract_left_binary(Args... args)
{
    return (1000 - ... - args); // 二元左折叠
}

// 辅助函数：打印展开过程
void print_expansion(const std::string &name, int result, const std::string &expansion)
{
    std::cout << name << ":\n";
    std::cout << "结果: " << result << "\n";
    std::cout << "展开式: " << expansion << "\n\n";
}
int main()
{
    print(1, 2.0, "Hello"); // 输出: 1 2 Hello

    // 测试所有四种折叠表达式
    int result1 = sum_right_unary(1, 2, 3, 4);
    print_expansion("一元右折叠", result1,
                    "1 + (2 + (3 + 4))");

    int result2 = sum_left_unary(1, 2, 3, 4);
    print_expansion("一元左折叠", result2,
                    "((1 + 2) + 3) + 4");

    int result3 = sum_right_binary(1, 2, 3, 4);
    print_expansion("二元右折叠", result3,
                    "1 + (2 + (3 + (4 + 100)))");

    int result4 = sum_left_binary(1, 2, 3, 4);
    print_expansion("二元左折叠", result4,
                    "((((100 + 1) + 2) + 3) + 4)");

    // 使用6个参数测试
    int result11 = subtract_right(100, 50, 25, 10, 5, 2);
    print_expansion("一元右折叠", result11,
                    "100 - (50 - (25 - (10 - (5 - 2))))"
                    "\n计算过程: 100 - (50 - (25 - (10 - 3)))"
                    "\n         = 100 - (50 - (25 - 7))"
                    "\n         = 100 - (50 - 18)"
                    "\n         = 100 - 32"
                    "\n         = 68");

    int result21 = subtract_left(100, 50, 25, 10, 5, 2);
    print_expansion("一元左折叠", result21,
                    "(((((100 - 50) - 25) - 10) - 5) - 2)"
                    "\n计算过程: ((((50 - 25) - 10) - 5) - 2)"
                    "\n         = (((25 - 10) - 5) - 2)"
                    "\n         = ((15 - 5) - 2)"
                    "\n         = (10 - 2)"
                    "\n         = 8");

    int result31 = subtract_right_binary(100, 50, 25, 10, 5, 2);
    print_expansion("二元右折叠", result31,
                    "100 - (50 - (25 - (10 - (5 - (2 - 1000)))))"
                    "\n计算过程: 100 - (50 - (25 - (10 - (5 - (-998)))))"
                    "\n         = 100 - (50 - (25 - (10 - 1003)))"
                    "\n         = 100 - (50 - (25 - (-993)))"
                    "\n         = 100 - (50 - 1018)"
                    "\n         = 100 - (-968)"
                    "\n         = 1068");

    int result41 = subtract_left_binary(100, 50, 25, 10, 5, 2);
    print_expansion("二元左折叠", result41,
                    "((((((1000 - 100) - 50) - 25) - 10) - 5) - 2)"
                    "\n计算过程: (((((900 - 50) - 25) - 10) - 5) - 2)"
                    "\n         = ((((850 - 25) - 10) - 5) - 2)"
                    "\n         = (((825 - 10) - 5) - 2)"
                    "\n         = ((815 - 5) - 2)"
                    "\n         = (810 - 2)"
                    "\n         = 808");
}